#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <stdbool.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "carplayExt.h"
#include "carplayExtInterface.h"
#include <android/log.h>
#include <sys/system_properties.h>
#include <linux/netlink.h>

#include <iostream>
#include <cassert>
#include <string>
#include <vector>

//#include "a2dp_player.h"
//#include "apm.h"
//#include "bt_at_cmd.h"
#define TAG "ZXCarplay"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)

#define PROPERTY_VALUE_MAX 92
char custom_id[PROPERTY_VALUE_MAX];

#define KEY_LENGTH  256               // ???????
#define PUB_KEY_FILE "/sdcard/local/tmp/suding/pubkey.pem"    // ��Կ·��
char g_pub_key[KEY_LENGTH];

static SdCarplay*          gCarplayHandle;
SdCarplay::LinkType g_carplay_type;

enum PlatformStatus {
    PLATFORM_INIT_OK = 0x00,
    PLATFORM_NO_SD_LINK = 0x01,
    PLATFORM_CHECK_MFI_FAILED = 0x02
};

class SdCarplayCallbacks : public ICarplayCallbacks {
  public:
    SdCarplayCallbacks(void* pctx) : mCtx(pctx) {}
    void carplaySessionStart();
    void carplaySessionStop();
    int switchUsbModeCB(UsbMode mode);
    void appleTimeUpdateCB(long long time);
    void appleLanguageUpdateCB(const char* lang);

    void appleCallStateUpdateCB(const char* remoteId,
                                const char* displayName,
                                int status,
                                int direction,
                                const char* uuid,
                                const char* addrBookId,
                                const char* label,
                                int service) ;

    void NotifyDeviceNameCB(const char* name, int name_len);
    void carplayExitCB();
    void returnNativeUICB();
    void modesChangeCB(CarPlayModeState* modes);
    void disableBluetoothCB();
    int iap2WriteData(char* buf, int len);

    void caplayDuckAudioCB(double inDurationSecs, double inVolume);
    void caplayUnduckAudioCB(double inDurationSecs);

    void carplayAudioStartCB(int handle, CarplayAudioStreamType type, int rate, int bits, int channels);
    void carplayAudioStopCB(int handle, CarplayAudioStreamType type);

    int carplayVideoStartCB();
    void carplayVideoStopCB();
    int carplayVideoDataProcCB(const char* buf, int len);

  private:
    void* mCtx;
};

void SdCarplayCallbacks::carplaySessionStart() {
    LOGV("%s:%d\n", __func__, __LINE__);
}

void SdCarplayCallbacks::carplaySessionStop() {
    LOGV("%s:%d\n", __func__, __LINE__);
//    if (g_carplay_type == SdCarplay::CARPLAY_WL) {
//        gCarplayHandle->stop();
//    }
}

bool  usb_mode  = false;
int platfrom_usb_switch_device() {
    struct sockaddr_un addr;
    int fd;
    char sock_path[128] = {"/dev/socket/sd_carplay"};
    const char* config_dir;

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        return 0;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        LOGV("sd_carplay no run\n");
        close(fd);
        return 0;
    }

    char buffer[40]= {0};
    write(fd,"AT#CF\r\n",7);

    int len = read(fd,buffer,sizeof(buffer)-1);
    if (len > 0) {
        if (strcmp(buffer,"OKCF\r\n")==0) {
            close(fd);
            return 1;
        }
        else if (strcmp(buffer,"ERRCF\r\n")==0) {
            close(fd);
            return 0;
        }
    }

    close(fd);
    return 0;
}
int platfrom_usb_switch_host() {
    struct sockaddr_un addr;
    int fd;
    char sock_path[128] = {"/dev/socket/sd_carplay"};
    const char* config_dir;

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        LOGV("sd_carplay no run\n");
        close(fd);
        return PLATFORM_NO_SD_LINK;
    }

    char buffer[40]= {0};
    write(fd,"AT#CG\r\n",7);

    int len = read(fd,buffer,sizeof(buffer)-1);
    if (len > 0 && strcmp(buffer,"OKCG\r\n")==0) {
    }

    close(fd);
    return 0;
}
int platfrom_usb_delete_link() {
    struct sockaddr_un addr;
    int fd;
    char sock_path[128] = {"/dev/socket/sd_carplay"};
    const char* config_dir;

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        LOGV("sd_carplay no run\n");
        close(fd);
        return PLATFORM_NO_SD_LINK;
    }

    char buffer[40]= {0};
    write(fd,"AT#CJ\r\n",7);

    int len = read(fd,buffer,sizeof(buffer)-1);
    if (len > 0 && strcmp(buffer,"OKCJ\r\n")==0) {
    }

    close(fd);
    return 0;
}
int platfrom_usb_switch_init() {
    struct sockaddr_un addr;
    int fd;
    char sock_path[128] = {"/dev/socket/sd_carplay"};
    const char* config_dir;

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        LOGV("sd_carplay no run\n");
        close(fd);
        return PLATFORM_NO_SD_LINK;
    }

    char buffer[40]= {0};
    write(fd,"AT#CD\r\n",7);

    int len = read(fd,buffer,sizeof(buffer)-1);
    if (len > 0 && strcmp(buffer,"OKCD\r\n")==0) {
    }

    close(fd);
    return 0;
}
int platfrom_usb_switch_deinit() {
    struct sockaddr_un addr;
    int fd;
    char sock_path[128] = {"/dev/socket/sd_carplay"};
    const char* config_dir;

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        LOGV("sd_carplay no run\n");
        close(fd);
        return PLATFORM_NO_SD_LINK;
    }

    char buffer[40]= {0};
    write(fd,"AT#CE\r\n",7);

    int len = read(fd,buffer,sizeof(buffer)-1);
    if (strcmp(buffer,"OKCE\r\n")==0) {

    }

    close(fd);
    return 0;
}
int SdCarplayCallbacks::switchUsbModeCB(UsbMode mode) {
    LOGV("##################################################%s:%d\n", __func__, __LINE__);
    int ret = 0;
    ret = platfrom_usb_switch_device();
    usb_mode = true;
    LOGV("##################################################%s:%d ret=%d\n", __func__, __LINE__,ret);
    return ret;
}

void SdCarplayCallbacks::appleTimeUpdateCB(long long time) {
    LOGV("%s:%d\n", __func__, __LINE__);
}

void SdCarplayCallbacks::appleLanguageUpdateCB(const char* lang) {
    LOGV("%s:%d\n", __func__, __LINE__);
}
void SdCarplayCallbacks::appleCallStateUpdateCB(const char* remoteId,
                                                const char* displayName,
                                                int status,
                                                int direction,
                                                const char* uuid,
                                                const char* addrBookId,
                                                const char* label,
                                                int service) {
    LOGV("%s:%d\n", __func__, __LINE__);
}
void SdCarplayCallbacks::NotifyDeviceNameCB(const char* name, int name_len) {
    LOGV("%s:%d\n", __func__, __LINE__);
}

void SdCarplayCallbacks::carplayExitCB() {
    LOGV("%s:%d usb_mode=%d\n", __func__, __LINE__,usb_mode);

    if (usb_mode == true) {
        LOGV("%s:%d\n", __func__, __LINE__);
        platfrom_usb_switch_deinit();
    }
    usb_mode = false;
}

void SdCarplayCallbacks::returnNativeUICB() {
    LOGV("%s:%d\n", __func__, __LINE__);
}

void SdCarplayCallbacks::modesChangeCB(CarPlayModeState* modes) {
    LOGV("%s:%d\n", __func__, __LINE__);
}

void SdCarplayCallbacks::disableBluetoothCB() {
    printf("%s:%d\n", __func__, __LINE__);
//    int fd;
//    const char* bt_path = "/dev/rf_serial";
//    if ((fd = open(bt_path, O_RDWR|O_NOCTTY|O_NDELAY)) == -1) {
//         printf("xxxxx open BluetoothCB Failed! \n");
//        LOGV("open /dev/zj_bt_serial failed!, err:", strerror(errno));
//        return;
//    }
//    int l = write(fd, "AT#CD\r\n", 7);
//    if (l < 0) {
//        printf("xxxxx open BluetoothCB Failed! \n");
//        LOGV("write BluetoothCB failed, error = %s", strerror(errno));
//        close(fd);
//    }
//    printf("write ok, len = %d", l);
//
//    char buffer[1024]={0};
//    while(1){
//        l = read(fd, buffer, sizeof(buffer));
//        if (l > 0) {
//            break;
//        }
//    }
//
//    LOGV("read len = %d, buffer = %s", l, buffer);
//    if (!strncmp (buffer, "IA", 2)) {
//        printf("xxxxx disableBluetoothCB OK! \n");

//    }

}

void SdCarplayCallbacks::caplayDuckAudioCB(double inDurationSecs, double inVolume) {
    LOGV("%s:%d\n", __func__, __LINE__);
}

void SdCarplayCallbacks::caplayUnduckAudioCB(double inDurationSecs) {
    LOGV("%s:%d\n", __func__, __LINE__);
}

int SdCarplayCallbacks::iap2WriteData(char* buf, int len) {
    LOGV("%s:%d len=%d\n", __func__, __LINE__,len);
    return 0;
    //return send_iap_data(buf,len);
}


#include <iostream>
#include <list>
#include <numeric>
#include <algorithm>
#include <pthread.h>
using namespace std;


static void* audio_play_process(void* ctx);
static void* audio_record_process(void* ctx);
class audioCtx {
  public:
    audioCtx(int handle, CarplayAudioStreamType type, int rate, int bits, int channels) :
        mHandle(handle), mType(type), mRate(rate), mBits(bits), mChannels(channels),
        mPidPtr(NULL) {
        int ret = -1;
        LOGV("%s:%d type=%d\n", __func__, __LINE__, type);
        if (type == AudioStreamRec) {
            //mAudioTrackHandle = audiotrack_record_start(rate, channels, bits, (int)type);
            //if(mAudioTrackHandle != NULL)
            //{
            //  apm_start(rate, channels, bits);
            //}
        }
        else {
            //mAudioTrackHandle = a2dp_player_start(rate, channels, bits, (int)type);
        }
        if (NULL == mAudioTrackHandle) {
            LOGV("%s:%d\n", __func__, __LINE__);
            return;
        }

        mStart = true;
        if (type == AudioStreamRec) {
            LOGV("%s:%d\n", __func__, __LINE__);
#if 0
            pthread_attr_t  attr;
            struct sched_param sched;
            int rs;
            rs = pthread_attr_init(&attr);
            pthread_attr_setschedpolicy(&attr,SCHED_RR);
            sched.sched_priority = 51;
            pthread_attr_setschedparam(&attr,&sched);
            ret = pthread_create(&mPid, &attr, audio_record_process, (void*)this);
#else
            ret = pthread_create(&mPid, NULL, audio_record_process, (void*)this);
#endif
        }
        else {
            LOGV("%s:%d\n", __func__, __LINE__);
#if 0
            pthread_attr_t  attr;
            struct sched_param sched;
            int rs;
            rs = pthread_attr_init(&attr);
            pthread_attr_setschedpolicy(&attr,SCHED_RR);
            sched.sched_priority = 51;
            pthread_attr_setschedparam(&attr,&sched);
            ret = pthread_create(&mPid, &attr, audio_play_process, (void*)this);
#else
            ret = pthread_create(&mPid, NULL, audio_play_process, (void*)this);
#endif
        }
        if (ret == 0) {
            mPidPtr = &mPid;
        }
    }
    virtual ~audioCtx() {
        LOGV("%s:%d\n", __func__, __LINE__);
        mStart = false;
        if (NULL != mPidPtr) {
            pthread_join(mPid, NULL);
            mPidPtr = NULL;
        }

        if (mType == AudioStreamRec) {
            //audiotrack_record_stop(mAudioTrackHandle);
            //apm_stop();
        }
        else {
            //a2dp_player_stop(mAudioTrackHandle);
        } LOGV("%s:%d\n", __func__, __LINE__);

    }
    int getAudioHandle() {
        return mHandle;
    }
    CarplayAudioStreamType getAudioStreamType() {
        return mType;
    }
    void* getAudioTrackHandle() {
        return mAudioTrackHandle;
    }

    friend void* audio_play_process(void* ctx);
    friend void* audio_record_process(void* ctx);
  private:
    int mHandle, mRate, mBits, mChannels;
    CarplayAudioStreamType mType;
    pthread_t mPid, *mPidPtr;
    bool mStart;
    void* mAudioTrackHandle;
};

uint64_t UpTicks(void) {
    uint64_t            nanos;
    struct timespec     ts;

    ts.tv_sec  = 0;
    ts.tv_nsec = 0;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    nanos = ts.tv_sec;
    nanos *= 1000000000;
    nanos += ts.tv_nsec;
    return nanos;
}

//#define DUMP_PLAY_PCM

#define AUDIO_BUFFER_MAX_SIZE 48*100*2*2 //100ms rate 48000, channel 2 bit 16

static void* audio_play_process(void* ctx) {
    int* ret;
    audioCtx* pctx = (audioCtx*)ctx;
    SdCarplay*          carplayHandle = gCarplayHandle;
    if (NULL == carplayHandle || NULL == pctx) {
        return NULL;
    }

    char buf[AUDIO_BUFFER_MAX_SIZE] = {0};
    char buf_out[AUDIO_BUFFER_MAX_SIZE+1024] = {0};
    unsigned int buf_len = 0;//len / (bits / 8 * channels)
    unsigned int buf_out_len = 0;

    int delay_ms = 20;//music
    if (pctx->mType == AudioStreamCall || pctx->mType == AudioStreamRECOGNITION) {
        delay_ms = 20;//call 20ms
    }
    else {

    }

    buf_len = (pctx->mRate*delay_ms/1000) * (pctx->mBits / 8 * pctx->mChannels);

    int frames = buf_len / (pctx->mBits / 8 * pctx->mChannels);
    int delay_us = (int)((int64_t)frames * 1000000 / pctx->mRate);
#ifdef DUMP_PLAY_PCM
    FILE* pf = fopen("/data/music.pcm", "w+");//淇濇寔澹伴煶鏁版�?
#endif

    LOGV("##%s:%d delay=%d bits=%d ch=%d rate=%d buf_len=%d frames=%d\n", __func__, __LINE__, delay_us, pctx->mBits,
         pctx->mChannels, pctx->mRate,buf_len,frames);
    //sleep(1);//妯℃嫙澹板崱寮�惎锛屽彲鑳戒笉闇�杩欎箞涔�?

    buf_out_len = 0;
    while (pctx->mStart) {
        memset(buf,0,buf_len);
        carplayHandle->playStream(pctx->mHandle, (void*)buf, buf_len, frames, UpTicks());
        //  //鐢ㄥ欢鏃舵潵妯℃嫙灏�?96涓瓧鑺傚０闊虫暟鎹挱鏀捐鐢ㄧ殑鏃堕棿
        //LOGV("%02x %02x %02x %02x %02x %02x %02x %02x", buf[0], buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]);
#if 1
        if (pctx->mType == AudioStreamCall || pctx->mType == AudioStreamRECOGNITION) {
#if 1
            buf_out_len = 0;
            //apm_farend(buf,buf_len,buf_out,&buf_out_len);
            //a2dp_player_write(pctx->mAudioTrackHandle, buf_out,buf_out_len);
            //LOGV("play buf_len:%d buf_out_len=%d",buf_len,buf_out_len);
#else
            a2dp_player_write(pctx->mAudioTrackHandle, buf,buf_len);
#endif
        }
        else {
            //a2dp_player_write(pctx->mAudioTrackHandle, buf,buf_len);
        }
#else
        usleep(delay_us);
#endif

#ifdef DUMP_PLAY_PCM
        fwrite(buf, 1, buf_len, pf);
#endif
    }
#ifdef DUMP_PLAY_PCM
    if (NULL != pf) {
        fclose(pf);
    }
#endif
    return ret ;
}

//#define DUMP_RECORD_PCM
#define AUDIO_RECORD_BUFFER_SIZE 16*100*2*2 //100ms rate 16000, channel 2 bit 16
static void* audio_record_process(void* ctx) {
    int* ret = 0;
    audioCtx* pctx = (audioCtx*)ctx;
    SdCarplay*          carplayHandle = gCarplayHandle;
    if (NULL == carplayHandle || NULL == pctx) {
        return NULL;
    }

    char buf[AUDIO_RECORD_BUFFER_SIZE] = {0};
    char buf_out[AUDIO_RECORD_BUFFER_SIZE+1024] = {0};

    unsigned int buf_len = 0;//len / (bits / 8 * channels)
    unsigned int buf_out_len = 0;

    int delay_ms = 20;//20ms
    buf_len = (pctx->mRate*delay_ms/1000) * (pctx->mBits / 8 * pctx->mChannels);

    int frames = buf_len / (pctx->mBits / 8 * pctx->mChannels);
    int delay_us = (int)((int64_t)frames * 1000000 / pctx->mRate);
    int ilen = 0;
#ifdef DUMP_RECORD_PCM
    FILE* pf = fopen("/data/rec.pcm", "w+");//淇濇寔澹伴煶鏁版�?
#endif

    LOGV("##%s:%d delay=%d bits=%d ch=%d rate=%d buf_len=%d\n", __func__, __LINE__, delay_us, pctx->mBits, pctx->mChannels,
         pctx->mRate,buf_len);
    //usleep(100000);
    while (pctx->mStart) {
        //ilen = audiotrack_record_read(pctx->mAudioTrackHandle, buf, buf_len);
        if (ilen > 0) {
            //usleep(delay_us);
#if 1
            buf_out_len = 0;
            //apm_nearend(buf,ilen,buf_out,&buf_out_len);
            frames = buf_out_len / (pctx->mBits / 8 * pctx->mChannels);
            //LOGV("rec ilen:%d buf_out_len=%d frames=%d",ilen,buf_out_len,frames);
            carplayHandle->recordStream(pctx->mHandle, (void*)buf_out, buf_out_len, frames, UpTicks());
#else
            frames = ilen / (pctx->mBits / 8 * pctx->mChannels);
            carplayHandle->recordStream(pctx->mHandle, (void*)buf, ilen, frames, UpTicks());
#endif
            //LOGV("rec-->%02x %02x %02x %02x %02x %02x %02x %02x", buf_out[0], buf_out[1],buf_out[2],buf_out[3],buf_out[4],buf_out[5],buf_out[6],buf_out[7]);
        }
    }
#ifdef DUMP_RECORD_PCM
    if (NULL != pf) {
        fclose(pf);
    }
#endif
    return ret;
}

static list<audioCtx*> gAudioHandles;
static pthread_mutex_t   gaudioListLock = PTHREAD_MUTEX_INITIALIZER;
void SdCarplayCallbacks::carplayAudioStartCB(int handle, CarplayAudioStreamType type, int rate, int bits,
                                             int channels) {
    audioCtx* pctx = NULL;

    LOGV("%s:%d\n", __func__, __LINE__);
    if (type == AudioStreamAlt) {
        list<audioCtx*>::iterator itor;
        audioCtx* tmpAudioHandle = NULL;

        pthread_mutex_lock(&gaudioListLock);
        for (itor = gAudioHandles.begin(); itor != gAudioHandles.end();) {
            tmpAudioHandle = *itor;
            if (tmpAudioHandle->getAudioStreamType() == AudioStreamMedia) {
                LOGV("%s:%d\n", __func__, __LINE__);
                if (tmpAudioHandle->getAudioTrackHandle() != NULL) {
                    //a2dp_player_setvol(tmpAudioHandle->getAudioTrackHandle(),0.5);
                }
                break;
            }
            else {
                itor++;
            }
        }
        LOGV("%s:%d\n", __func__, __LINE__);

        pthread_mutex_unlock(&gaudioListLock);
    }


    pctx = new audioCtx(handle, type, rate, bits, channels);

    pthread_mutex_lock(&gaudioListLock);
    gAudioHandles.push_back(pctx);
    pthread_mutex_unlock(&gaudioListLock);

}
void SdCarplayCallbacks::carplayAudioStopCB(int handle, CarplayAudioStreamType type) {
    list<audioCtx*>::iterator itor;
    audioCtx* tmpAudioHandle = NULL;
    bool isFound = false;

    LOGV("%s:%d,type=%d\n", __func__, __LINE__,type);
    pthread_mutex_lock(&gaudioListLock);
    for (itor = gAudioHandles.begin(); itor != gAudioHandles.end();) {
        tmpAudioHandle = *itor;
        if (tmpAudioHandle->getAudioHandle() == handle) {
            isFound = true;
            LOGV("%s:%d\n", __func__, __LINE__);
            gAudioHandles.erase(itor);
            break;
        }
        else {
            itor++;
        }
    }
    LOGV("%s:%d\n", __func__, __LINE__);

    pthread_mutex_unlock(&gaudioListLock);

    if (isFound) {
        delete tmpAudioHandle;
    }

    if (type == AudioStreamAlt) {
        list<audioCtx*>::iterator itor;
        audioCtx* tmpAudioHandle = NULL;

        pthread_mutex_lock(&gaudioListLock);
        for (itor = gAudioHandles.begin(); itor != gAudioHandles.end();) {
            tmpAudioHandle = *itor;
            if (tmpAudioHandle->getAudioStreamType() == AudioStreamMedia) {
                LOGV("%s:%d\n", __func__, __LINE__);
                if (tmpAudioHandle->getAudioTrackHandle() != NULL) {
                    //a2dp_player_setvol(tmpAudioHandle->getAudioTrackHandle(),1.0);
                }
                break;
            }
            else {
                itor++;
            }
        }
        LOGV("%s:%d\n", __func__, __LINE__);

        pthread_mutex_unlock(&gaudioListLock);
    }
}

int SdCarplayCallbacks::carplayVideoStartCB() {
    LOGV("%s:%d\n", __func__, __LINE__);

    return 0;
}
void SdCarplayCallbacks::carplayVideoStopCB() {
    LOGV("%s:%d\n", __func__, __LINE__);
}
int SdCarplayCallbacks::carplayVideoDataProcCB(const char* buf, int len) {
    //LOGV("%s:%d len=%d\n", __func__, __LINE__, len);
    return 0;
}

#define UEVENT_BUFFER_SIZE 2048

static int init_hotplug_sock() {

    const int buffersize = 1024;
    int ret;
    struct sockaddr_nl snl;
    bzero(&snl, sizeof(struct sockaddr_nl));

    snl.nl_family = AF_NETLINK;
    snl.nl_pid = 0;//getpid();
    snl.nl_groups = 1;

    int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    if (s == -1) {
        LOGV("init_hotplug_sock: socket err\n");
        return -1;
    }

    setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
    ret = ::bind(s, (struct sockaddr*)&snl, sizeof(struct sockaddr_nl));
    if (ret < 0) {
        LOGV("init_hotplug_sock: bind err\n");
        close(s);
        return -1;
    }

    return s;
}

#define KEYVALLEN 256
static int sd_get_config_string(char* path, char* key, char keylen, char* val, char vallen) {
    FILE* fp;
    char buf[KEYVALLEN] = {0};
    int ret = 0;

    if ((fp = fopen(path, "r"))==NULL) {
        return ret;
    }

    while (!feof(fp) && fgets(buf, KEYVALLEN, fp) !=NULL) {
        if (!strncmp(buf, key, keylen)) {
            memcpy(val, buf + (keylen + 1), vallen);
            ret = 1;
            break;
        }
    }
    fclose(fp);
    return ret;
}

static void process_usb_netlink_info(char* buf) {
    char*  tmp = NULL, path[1024] = {0};
    char key[32] = {0}, val[128]= {0};
    int idProduct = 0, idVendor = 0;
    int online = 0;

    if (!strncmp(buf, "add", 3)) {
        tmp = strchr(buf, '@');
        if (tmp == NULL) {
            return;
        }
        tmp += 1;
        sprintf(path, "/sys%s/uevent", tmp);
        LOGV("@@@%s:%d \n", __func__, __LINE__);
        if (0 == sd_get_config_string(path, "DEVTYPE", 7, val, sizeof(val))) {
            return;
        }
        if (strncmp(val, "usb_device", strlen("usb_device"))) {
            return;
        }
        memset(val, 0, sizeof(val));
        if (0 == sd_get_config_string(path, "PRODUCT", 7, val, sizeof(val))) {
            return;
        }

        sscanf(val, "%x/%x/", &idVendor, &idProduct);
        if (idVendor == 0x05ac) {
            LOGV("@@@%s:%d idVendor=0x%04x\n", __func__, __LINE__,idVendor);
            SdCarplay::CarplayState state= gCarplayHandle->getCarplayState();
            LOGV("getCarplayState=%d\n",state);
            //if(state == SdCarplay::CarplayStateInit || state == SdCarplay::CarplayStateExit)
            {
                gCarplayHandle->setValue("LINK_TYPE", SdCarplay::CARPLAY);
                platfrom_usb_delete_link();
                gCarplayHandle->start(SdCarplay::CARPLAY, SdCarplay::Mode0);
            }
        }

    }
    else if (!strncmp(buf, "remove", 6)) {
        tmp = strchr(buf, '@');
        if (tmp == NULL) {
            return;
        }
        tmp += 1;
        sprintf(path, "/sys%s/uevent", tmp);
        //LOGV("\033[;31m%s:%d remove path=%s \033[0m\n", __func__, __LINE__, path);
    }
}

static void* usb_detect_process(void* ctx) {
    int* ret = 0 ;
    char buf[UEVENT_BUFFER_SIZE * 2] = {0};
    int hotplug_sock = init_hotplug_sock();
    while (hotplug_sock > 0) {
        /* Netlink message buffer */
        recv(hotplug_sock, &buf, sizeof(buf), 0);
        //LOGV("usb_detect_process:%s\n", buf);
        //if(strcmp(buf,"bind@/devices/platform/ff300000.usb/usb1/1-1") == 0)
        process_usb_netlink_info(buf);
    }
    if (hotplug_sock > 0) {
        close(hotplug_sock);
    }
    return ret;
}

int check_mfi_and_sd_carplay(void) {
    struct sockaddr_un addr;
    int fd;
//    char sock_path[128] = {"/dev/socket/sd_carplay"};
    char sock_path[128] = {"/dev/socket/evilink"};
    const char* config_dir;

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        return -1;
    }

    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags &(~O_NONBLOCK));

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        LOGV("sd_carplay no run\n");
        close(fd);
        return PLATFORM_NO_SD_LINK;
    }

    char buffer[40]= {0};
    write(fd,"AT#CC\r\n",7);
    LOGV("check_mfi_and_sd_carplay write CC");

    int len = read(fd,buffer,sizeof(buffer)-1);
    if (len > 0) {
        if (strcmp(buffer,"OKCC\r\n")==0) {
            close(fd);
            return 0;
        }
        else if (strcmp(buffer,"ERRCC\r\n")==0) {
            LOGV("NO MFI chip\n");
            close(fd);
            return PLATFORM_CHECK_MFI_FAILED;
        }
    }

    close(fd);
    return 0;
}
static char uuid[2048];
int get_mfi_uuid() {
    int size=sizeof(uuid);
    struct sockaddr_un addr;
    int fd;
//    char sock_path[128] = {"/dev/socket/sd_carplay"};
    char sock_path[128] = {"/dev/socket/evilink"};
    const char* config_dir;

    if (size < 2048) {
        return -1;
    }
    memset(uuid,0,size);

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        return -1;
    }

    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags &(~O_NONBLOCK));

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        LOGV("sd_carplay no run\n");
        close(fd);
        return PLATFORM_NO_SD_LINK;
    }

    char buffer[40]= {0};
    write(fd,"AT#CA\r\n",7);

    char tmp[2048] = {0};
    int len = read(fd,tmp,sizeof(tmp));
    LOGV("read uuid:%s\n",tmp);
    if (len > 0) {
        if (strcmp(tmp,"ERRCA\r\n")==0) {
            LOGV("NO MFI chip\n");
            close(fd);
            return PLATFORM_CHECK_MFI_FAILED;
        }
        else {
            if (len > 4 && tmp[0] == 'C' && tmp[1] == 'A' && tmp[len-2] == '\r' && tmp[len-1] == '\n') {
                strncpy(uuid,tmp+2,len-4);
                close(fd);
                return len-4;
            }
        }
    }

    close(fd);
    return 0;
}

void connect_carplay_wl(char mac[6],char* local_mac,char bt_iap) {
    if (gCarplayHandle) {
        SdCarplay::CarplayState state= gCarplayHandle->getCarplayState();
        char local_mac_addr[12+6];
        memset(local_mac_addr,0,sizeof(local_mac_addr));
        strncpy(local_mac_addr,local_mac,2);
        strcat(local_mac_addr,":");
        strncat(local_mac_addr,local_mac+2,2);
        strcat(local_mac_addr,":");
        strncat(local_mac_addr,local_mac+4,2);
        strcat(local_mac_addr,":");
        strncat(local_mac_addr,local_mac+6,2);
        strcat(local_mac_addr,":");
        strncat(local_mac_addr,local_mac+8,2);
        strcat(local_mac_addr,":");
        strncat(local_mac_addr,local_mac+10,2);


        LOGV("getCarplayState=%d local_mac_addr:%s local_mac:%s\n",state,local_mac_addr,local_mac);
        //if(state == SdCarplay::CarplayStateInit || state == SdCarplay::CarplayStateExit)
        {
            gCarplayHandle->setValue("BTMAC", local_mac_addr);
            gCarplayHandle->setValue("LINK_TYPE", SdCarplay::CARPLAY_WL);
            gCarplayHandle->setBtAddr(mac);
            gCarplayHandle->start(SdCarplay::CARPLAY_WL, SdCarplay::Mode0);
        }
    }
}

int carplay_readIap2DataProc(char* buf, int len) {
    int ret = -1;
    if (gCarplayHandle) {
        ret = gCarplayHandle->readIap2DataProc(buf,len);
    }
    return ret;
}

void on_bluetooth_connect_state(int state) {

}
void on_phone_bluetooth_name(char* name) {

}

static bool start = false;
void sighandler(int sig) {
    LOGV("receive a signal --> SIGINT\n");
    start = false;
}
#define MAX_CMDLINE_LENGTH 256
static void enter_command_mode() {
    char cmd[MAX_CMDLINE_LENGTH];
    char c = 0;
    int i = 0;
    do {
        i = 0;
        printf("Input command>> ");
        fflush(stdout);
        memset(cmd, 0, MAX_CMDLINE_LENGTH);
        scanf("%s", cmd);

        if (strncmp(cmd, "Q", 1) == 0) {
            system("cat /sys/devices/platform/soc/usbc0/usb_host");
            break;
        }
        else if (strncmp(cmd, "\n", 1) == 0) {
            // treat as resetting the screen.
            continue;
        }
        else {
            printf("Error command.\n");
            continue;
        }

    }
    while (1);
}


int main(int argc, char** argv) {
    int ret;
    SdCarplay*          carplayHandle;
    SdCarplayCallbacks*   carplayCBs;

    signal(SIGINT, sighandler);

    carplayCBs = new SdCarplayCallbacks(NULL);
    carplayHandle = new SdCarplay(carplayCBs);
    gCarplayHandle = carplayHandle;
    g_carplay_type = SdCarplay::CARPLAY;//SdCarplay::CARPLAY_WL;


    __system_property_get("sys.suding.custom",custom_id);
    LOGV("sys.suding.custom:%s\n",custom_id);
    //  if(g_carplay_type == SdCarplay::CARPLAY)
    //  {
    //      platfrom_usb_switch_init();
    //  }

    // if((ret = check_mfi_and_sd_carplay()) != PLATFORM_INIT_OK)
    //  {
    //      return ret;
    //  }

    LOGV("sys.suding.custom:%s\n",custom_id);

    //  get_mfi_uuid();

// 初始化
    carplayHandle->init();
    char btmac[6] = {0x80, 0x0C, 0x67, 0xA8, 0x2E, 0xAF};
//    carplayHandle->setBtAddr(btmac);//设置要连接手机的蓝牙地址


#if 0
    FILE* pubFile = fopen(PUB_KEY_FILE, "r");

    memset(g_pub_key,0,KEY_LENGTH);
    int len = fread(g_pub_key, 1, KEY_LENGTH, pubFile);
    std::string clearText = "suding";
    std::string pub_str(g_pub_key);

    std::string g_priv_key = carplayHandle->rsaPubEncrypt(clearText,pub_str);
    carplayHandle->setEncryptText(g_priv_key);
#endif

    pthread_t tid;
    ret = pthread_create(&tid, NULL, usb_detect_process, NULL);
    /*if(open_bt_uart() < 0)//open virtual
    {
     //open rfcomm
     if(open_iap_rfcomm()==0)
     {

     }
    }
    */

//    carplayHandle->start(SdCarplay::CARPLAY, SdCarplay::Mode0);

    carplayHandle->start(g_carplay_type, SdCarplay::Mode0);
    LOGV("%s:%d\n", __func__, __LINE__);
    start = true;

    enter_command_mode();
    carplayHandle->stop();

    delete (carplayHandle);
    delete (carplayCBs);

    return 0;
}
